GHGDroid(异构图):Global heterogeneous graph-based android malware detection
1 介绍
随着移动网络建设的加快和智能手机的广泛使用,恶意软件,特别是Android平台的恶意软件在应用市场上猖獗,因为新兴的自动化恶意软件生成工具(Avpass:泄漏和绕过反病毒检测模型;Android恶意软件即将变得更糟:GM Bot源代码)。恶意软件表现出各种各样的恶意行为,导致用户财产损失或隐私泄露,对广告管理员来说,及时阻止恶意软件发布是一个巨大的挑战。为了应对这一挑战,Android应用市场部署了各种恶意软件检测工具(VirusTotal;VirScan;Ye et al., 2019),以确定开发人员提交的应用程序是否存在恶意行为。然而,检测的准确性和效率仍然不尽人意(Razgallah et al., 2021)。因此,准确高效的Android恶意软件检测方法和工具仍然受到学术界和工业界越来越多的关注。传统方法(Enck et al., 2009;Seo et al., 2014;Zheng et al., 2013)通常涉及提取配置文件和源代码,通过预定义的规则或签名来检测漏洞或恶意代码。这种方法需要领域专家制定规则和庞大的指纹数据库进行匹配。此外,Android应用程序可以通过简单地混淆代码来绕过这些检测方法。为了解决这些问题,随着人工智能(AI)的发展,基于机器学习(ML)或深度学习(DL)的检测方法由于其准确性的显着提高而成为恶意软件检测和分类的有前途的解决方案,研究人员已经展示了他们的创造力和想象力,可以发现用于恶意软件检测的多样化和区别性特征,例如权限特征,API特征,字节码特征,元数据,以及高级的基于图形的功能。尤其是在这些特性中,基于图形的特性更受关注,因为像控制流图(cdg)、函数调用图(fcg)和数据流图(DFGs)这样的图形,通过提取特定的软件组件作为节点,提取组件之间的关系作为边来构建,可以从多个角度很好地表征一个复杂的Android应用程序。并且,利用图挖掘技术,可以自动捕获丰富的基于图的特征,以便更准确地检测恶意软件。尽管基于图的方法实现了较高的检测准确率,但仍然存在假阴性和假阳性的问题,特别是高假阴性。此外,它们通常面临构建与检测下APK对应的图的计算成本高的问题。为了解决这些问题,本文开发了一种新的全局异构图GHG,并提出了一种基于图的Android恶意软件检测方法GHGDroid,该方法通过精心设计的图嵌入技术,利用从GHG中自动学习到的基于图的特征。为了从全局角度表征APK和敏感API (SAPI)之间以及敏感API之间的复杂关系,通过从给定的大规模训练APK中提取SAPI和API调用序列,并通过两种类型的边(APK-SAPI和SAPI-SAPI)连接节点,构建了GHG。构建的温室气体为进一步的基于图的特征提取提供了丰富而有用的信息,有助于缓解高假阴性的问题。此外,温室气体也易于更新。因此,可以将被检测的APK直接添加到温室气体中,提高了在线检测的效率,使其更适合于现实世界的检测场景。使用GHG, GHGDroid使用多阶邻居采样策略和多层基于gcn的网络来学习图中涉及的apk的节点嵌入。这些学习到的APK嵌入很好地捕获了它们区分恶意与良性的行为,这也有助于提高检测的准确性。根据APK的嵌入及其标签,恶意软件检测模型以监督的方式进行训练,并用于确定应用程序供应商提交的APK是否恶意。总之,主要贡献如下。
1)我们建立了一个全局异构图,不仅刻画了apk和sapi之间的复杂关系,而且从全局角度区分了恶意或良性apk的原生行为。此外,温室气体的良好可更新性使其适用于具有低检测时间开销的实际检测场景。
2)提出了一种基于多阶邻居采样和基于多层ergcn的APK表示学习相结合的温室气体图嵌入方法,前者从局部角度确定目标APK的上下文,后者聚集上下文信息进行判别APK嵌入。
3)我们对恶意/良性数据集进行了实验,以评估GHGDroid。实验结果表明,GHGDroid的准确率为98.99%,F1分数为99.17%,优于现有的方法。
本文的其余部分组织如下。第二节讨论了相关工作.第3节给出了Android恶意软件检测方法的总体框架,详细介绍了各部分的实现,并在基准数据集上进行了全面的实验,以评估模型的性能和各模块的有效性,第4节对检测效率进行了分析。第五部分简要总结了我们的工作。
2 相关工作
研究人员已投入大量精力开发了各种静态和动态特征(Avpass:漏洞利用与绕过反病毒检测模型)用于安卓恶意软件检测。由于我们的方法 GHGDriod 是基于从全局异构图中学习到的特征来进行检测的,因此我们从特征方面大致将其检测方法分为两类,即基于图的检测方法和其他检测方法,并对其进行了讨论。
2.1. 基于图的方法
2.1.1. 图构建
由于代码的独特结构形式,研究人员已经认识到普通的特征不足以捕捉 Android 恶意软件中的语义信息。然而,利用先进的结构特征能够增强特征的稳健性,并降低恶意应用程序开发者的修改成本。各种图,例如控制流图(CFG)、函数调用图(FCG)、数据流图(DFG)等,一直是研究人员关注的焦点。CFG 是一种在语句级别分析程序的模型。图中的每个节点代表代码中的一个基本块,而边则表示基本块之间的跳转关系。一个基本块是一个具有入口点和出口点的代码序列,并且使用有向边来表示执行期间的控制流跳转。多种代码(Alamet al.,2017;Sun 等人,2014)如源代码和 Dalvik 字节码,都可以用于构建 CFG。在更精细的粒度上构建图通常会耗费大量时间,并导致生成难以分析的大 CFG。研究人员采用灵活的方法来创建控制流图(CFG),例如通过分析程序语句来构建方法级别的 CFG(Marastoni 等人,2017 年)。此外,CFG 中节点之间的复杂关系及其较差的可解释性给图编码和同构分析带来了重大挑战。Fairbanks 等人(Fairbanks 等人,2021 年)将恶意操作与 ATT&CK 框架中列出的战术、技术和程序(TTP)相联系,以帮助理解恶意行为。他们提出了一种自动方法,在恶意软件控制流图的子图中定位 TTP。DFG(Crussel 等人,2012 年;Wolfe 等人,2014 年)的构建主要基于程序执行期间的数据传输分析。图中的每个节点代表一个与数据相关联的语句,边代表语句之间的数据依赖关系。DFG 的构建通常伴随着控制流图的构建。例如,Xu 等人(2019 年)将数据流图和控制流图作为分析特征进行组合使用。基于 FCG 的方法通常将函数调用表示为节点,而将表示调用关系的边描绘在这些节点之间。这些函数可以分为两类:由 Android 操作系统提供的系统函数,以及由开发人员定义的用户函数。通过分析 API 调用,可以构建一个 API 调用图,其中节点代表 API 函数,边代表它们之间的调用关系。基于 API 调用的图表示捕捉了 Android 软件的行为特征(V 和 D,2021;Feng 等人,2021;Pektaş 和 Acarman,2020)。然而,研究人员专注于子图挖掘(Zhao 等人,2021;Fan 等人,2017;Ou 和 Xu,2022),为每个 APK 构建完整的调用图是复杂且冗余的。他们对 API 调用图进行敏感子图或路径挖掘,以精确识别 Android 应用中的敏感行为。除了为单个 Android 应用构建图之外,还有另一种方法涉及为多个 APK 构建异构图(Gao 等人,2021;Hou 等人,2017),这有效地利用了来自全局和局部视角的信息。与同质图方法相比,异质图的关键在于它包含不同类型节点。通过将整个数据集视为一个单一的图,异质图能够捕捉全局和局部数据特征,同时简化图构建过程。
2.1.2. 基于图挖掘的检测模型
尽管使用基于图的结构特征能够有效地捕获代码的语义信息,但它们往往比传统特征具有显著更高的分析复杂度。图通常包含数千个节点,使得直接分析极其耗时。因此,需要高效的方法来提高分析效率。构建分类器的常见方法可以分为以下几类:传统的图分析方法、基于图嵌入的分类器、基于子图的特征提取分类器以及基于 GCN 的分类器。基于图的传统分析方法包括用于图相似性计算、图签名生成和图匹配的各种算法。这些方法通常依赖于已知样本,并通过将其与已知样本进行比较来对给定样本进行分类。Marastoni 等人(2017 年)构建了方法级别的控制流图,并将其编码为特征向量。他们设计了一种算法来测量代码相似性并计算相似性得分,以检测恶意软件。Alam 等人(2017 年)利用 MAIL 模式对软件中的控制流进行标注,以捕捉控制流语义。他们将软件分解为一系列较小的已标注控制流图(ACFG),作为其特征。在检测过程中,将特征的 ACFG 与已知恶意软件的 ACFG 进行比较,如果匹配比例较高,则该应用程序会被标记为恶意软件。近年来,深度学习作为一种先进的机器学习技术已在多个领域得到广泛应用。它在安卓恶意软件检测方面也表现出卓越的性能。我们可以将大量恶意软件样本的图表示输入深度神经网络模型进行训练,训练后的检测模型能够准确地检测和识别恶意软件。Feng 等人(2021 年)构建了 API 调用图,并利用算法计算图嵌入。然后将这些嵌入输入深度神经网络(DNN)以构建用于检测恶意软件的分类模型。Ye 等人(2019 年)提出了 HG-Learning,这是一种基于异构图的可扩展表示学习算法。随后,这些经过学习处理的表示被输入到一个深度神经网络分类器中以获取检测结果。将原始的大图分割成一系列子图是一种常见的方法,用于减小图的规模并提高识别效率。通过适当分割子图,可以消除图中的冗余信息。分割后,可以应用各种算法来处理这些子图,要么对其进行特征编码,要么生成图嵌入以表示整个 APK。然后,这些表示可以被输入到机器学习算法中以训练恶意软件检测模型。他们使用图论算法、图哈希或特征编码来将子图的特征表示为向量,最终通过这些子图反映整个 APK 的特征。DAPASA(Fan 等人,2017 年)基于函数调用图生成敏感子图,然后构建五个特征来描述这些敏感子图内的 API 调用模式。然后将这五个特征输入到机器学习算法中。欧和徐(2022 年)在函数调用图上标记敏感节点,并挖掘可疑子图(SSGs)和相邻可疑子图(NSGs)以表示软件的可疑行为。这些子图通过哈希编码转换为特征向量,并通过随机森林算法进行分类。
GCN(Kipf 和 Welling,2017)是一种基于图结构的方法,它通过卷积操作来学习图中节点和边的特征。安卓恶意软件的图结构通常规模庞大且结构复杂。GCN 能够处理复杂的图结构,使其非常适合用于安卓恶意软件检测。V. 和 J.(2021)为图中的每个节点构建了一个特征向量来表示其特征,并使用 GCN 进行嵌入学习和分类。Feng 等人(2021)在方法层面使用基于 smali 序列的嵌入,将 APK 中所有方法的嵌入组合成一个特征矩阵,并将其与函数调用图的邻接矩阵一起输入到图神经网络中进行节点分类。上述方法都使用 GCN 来学习同构图中的节点特征。然而,GCN 也可以用于异构图中的节点嵌入学习。Gao 等人(2021)提出了一种基于 APK 和 API 节点的异构图检测算法,与我们的 GHGDroid 最为相似。该图被转换为邻接矩阵以输入到 GCN 模型中。与高(Gao)所提出的方案相比,主要的不同之处在于以下几点。首先,GHGDroid 考虑了更为复杂的关联关系,它不仅考虑了恶意和良性应用程序之间 API 的调用频率和分布情况,还考虑了 APK 和 API 之间的调用关系,这有助于增强全局信息。其次,GHGDroid 为两种边赋予权重以表征节点之间关系的强度,这与高(Gao)的方法中的定性分析不同,是一种定量分析。最后,GHGDroid 可以在动态图上工作,无需重新训练检测模型。
2.2. 其他方面
传统特征,包括权限、API 调用、字节码等等,以字符串形式呈现,并包含语义信息。在特征工程中常见的做法是从 APK 中提取这些特征以获取用于模型训练的相应特征序列。权限是 Android 操作系统的一个重要组成部分,在该领域的研究工作中被广泛用作特征。Android 权限用于识别和限制访问权限、保护用户数据和隐私,并防止未经授权的访问和数据泄露。许多研究关注软件的权限特征,基于请求的权限来检测恶意应用程序。Arora 等人(2020 年)提出了一种 PermPair 方法,通过从 manifest.xml 文件中提取权限对来构建和比较恶意软件和良性软件。然而,权限只是 Android 软件中的基本特征,并且存在权限过度的问题,即使请求的权限也可能无法被利用。这可能是仅依赖此特征的检测方法面临性能瓶颈的原因之一,促使研究人员将其与其他特征相结合。费泽洛拉等人(2017 年)在其实验中表明,仅使用权限特征的检测率仅为 83%,而结合意图和权限特征的检测率达到了 95.5%。金等人(2019 年)进一步融合了基于存在性和基于相似性的特征,如字符串、权限、组件、操作码、API 等,并在安卓恶意软件检测中使用了多模态深度学习。安卓恶意软件通常在运行时通过调用系统 API 来从事诸如访问用户私人数据和安卓系统资源之类的恶意活动。系统 API 的本质使其具有一定程度的混淆抵抗能力,使得 API 调用在检测中非常有效。DroidAPIMiner(Aafer 等人,2013 年)专注于 API 调用、包级别信息和参数,分析恶意软件和良性软件以构建用于分类的 API 特征。SDAC(徐等人,2022 年)同样通过提取 API 调用序列来学习 API 向量,并通过 API 的语义距离对其进行聚类。然而,直接使用 API 特征会导致高维度和稀疏矩阵。此外,研究发现只有特定的 API 调用才能区分恶意软件,因此基于特定 API 进行了一系列工作。MalPat(陶等人,2018 年)仅关注与权限相关的敏感 API,并仅使用 50 个 API 的特征向量就取得了良好的结果。Yumlembam 等人(2023 年)提出了 BM25 作为衡量良性与恶意软件中 API 使用差异的指标,并帮助选择 1000 个最重要的 API 来训练检测模型。还有基于 API 调用构建行为模型的研究,MaMaDroid(Onwuzurike 等人,2019 年)通过在 API 序列上构建马尔可夫链模型实现了恶意软件检测。与汇编语言类似,字节码文件也有其自身的一组指令。每个指令都由相应的操作码以及操作数组成。在获得的操作码序列上使用 N-gram 技术。它使用步长为 N 的滑动窗口将操作码序列划分为 N 个操作码的子序列。这些子序列被提取为字节码特征以增强鲁棒性。Sihag 等人(2020 年)使用 N-gram 技术从字节码中提取特征,捕获相关的子序列特征。他们利用布隆过滤器来计算相似度度量以对安卓软件进行分类。巴特和杜塔(2021 年)提出了一种名为 CogramDroid 的新型恶意软件检测方法,该方法基于操作码 N-grams。它利用词语的概念来研究操作码 N-grams 的相对频率模式。孙和张(2022 年)针对 N-gram 特征的未充分利用问题,提出了一个基于加权 N-gram 特征的双路径恶意软件检测模型。从两个角度提取特征并进行加权处理,并与其他特征融合用于分类。
3 GHGDroid
在本节中,我们提出了一种新颖的基于全局异构图的 Android 恶意软件检测方法——GHGDroid。我们首先描述整个检测框架,随后介绍检测过程中涉及的各个组件。
3.1. 框架
图 1 描述了所提出的基于全局异构图的 Android 恶意软件检测方法 GHGDroid 的总体框架,该框架由三个关键组件构成,包括敏感 API 调用提取、全局异构图构建和图嵌入。首先,以这些准备好的 APK 作为输入,敏感 API 调用提取组件通过分析对应特定 APK 的 smali 文件来提取调用的 API,并通过指定敏感 API 集来识别敏感 API。其次,使用 SAPI 和 API 调用序列以及输入 APK,全局异构图构建组件使用 APK 和 SAPI 这两种类型的节点构建一个名为 GHG 的图,从全局和局部两个方面来表征 APK 和 SAPI 之间的关系。为了充分利用从大规模 APK 中提取的信息,GHGD(基于图的恶意软件检测框架)通过借鉴词向量学习中的 skip-gram 模型,为 APK 与 SAPI 之间的边以及两个 SAPI 之间的边赋予了不同的权重。这使得 GHG 更具信息量,并能更有效地捕捉 Android 应用的行为模式。此外,利用 GHG,GHG 嵌入组件通过采用多阶邻域采样策略并结合基于 GCN 的 APK 表示学习方法,为参与 GHG 的每个 APK 获取分布式表示。将这些组件以流水线方式组合起来,我们以恶意或良性标签的方式,在离线状态下对大规模 Android 应用程序训练恶意软件检测模型。为了判断某个应用供应商提交的 APK 是否为恶意软件,我们通过敏感 API 调用提取组件分析敏感 API 调用信息,并在构建的 GHG 中添加一个节点,然后使用 GHG 嵌入组件学习该节点的嵌入表示。最后,将 APK 的学习型节点嵌入信息输入到检测模型中,以获得检测结果,即恶意或良性。
3.2. 敏感 API 调用提取
Android 应用程序中的 API 可分为系统 API 和用户 API。系统 API 是由 Android 操作系统为应用程序提供的编程接口,用于控制和管理硬件资源。但用户 API 是由应用程序开发者自己设计的,通常利用系统 API 调用来实现特定功能。因此,通过捕获 API 调用来理解 Android 应用程序的行为是一种简单直接的方法。在先前的工作(Aafer 等人,2013 年;Onwuzurike 等人,2019 年)中,与 API 相关的特征在恶意软件检测中得到了广泛使用。一个 APK 可能会调用大量的 API,而恶意软件往往只在正常代码中嵌入少量恶意代码,并利用关键 API 来实现恶意目的。在这里,我们关注敏感 API,因为考虑所有 API 不仅会引入干扰信息,还会显著增加分析复杂性。为了获得尽可能完整的敏感 API 集,我们使用了两个具有代表性的工具 SuSi(Arzt 等人,2013 年)和 PScout(Au 等人,2012 年)的组合来识别敏感 API。这两款工具所提供的 API 被合并,形成了最终的集合,记为 SAPI = {sapi1,sapi2,...,sapiK},其中 K 表示敏感 API 的数量。利用这个敏感的 SAPI 集合,我们进一步分析 APK 的 smali 文件,以获取敏感 API 调用的统计信息以及敏感 API 的调用序列,这将在下一节中有助于构建一个全局异构图。在对 APK 文件进行反编译后,我们得到了一组 smali 文件,其中每个 smali 文件对应一个特定的 class 文件。通过分析一个 smali 文件,我们通过“.method”指令提取该类中的每个方法,通过“invoke-*”
指令检索每个方法中调用的敏感 API,并统计特定 APK 中每个敏感 API 的调用次数。因此,我们得到了一个 APK-SAPI 调用矩阵,如图 2 所示。同时,从每个方法中提取的 API 调用序列也被记录下来,如图 3 所示,其中灰色的 API 是敏感的。请注意,这些方法级别的序列也可能包含非敏感的系统 API 以及 SAPI。此外,我们通过依次将这些方法级序列中的敏感 API 连接起来的方式构建出类级别的 API 调用序列。
3.3. 全局异构图构建
为了捕捉有助于区分良性与恶意软件的结构特征,基于 APK 训练数据集构建了全局异构图,从全局和局部两个角度描绘了 APK 到 SAPI 以及 SAPI 到 SAPI 的复杂相互依赖关系。使用了由 Android 应用安全分析社区提供的大量已标注的 APK 来构建全局异构图。假设训练数据集表示为 APKs = {apk1, apk2, ..., apkN},其中 N 表示数据集的大小。全局异构图的正式定义见定义 1,随后是构建全局异构图的具体算法。定义 1. 全局异构图(GHG)。GHG = (V, E, W) 是一个异构图,包含两种类型的节点,V = VAPK ∪ VSAPI,其中 VAPK 和 VSAPI 分别表示 APK 节点集和 SAPI 节点集。同样,有两种类型的边 E = EAPK SAPI ∪ ESAPI SAPI,其中 EAPK SAPI 表示 APK 节点与 SAPI 节点之间的边,而 ESAPI SAPI 表示两个 SAPI 节点之间的边。W 表示与边集 E 相对应的边权重集合,其中权重用于衡量节点之间关系的强度。
现在我们分别给出两种类型的边(APK-SAPI 边和 SAPI-SAPI 边)的边权重分配方法。3.3.1. APK-SAPI 边缘权重分配
对于某一特定的温室气体(GHG),在 APK 和 SAPI 之间存在着多对多的依赖关系。换句话说,一个 APK 节点可能会由于 API 调用而连接到多个 SAPI 节点,反之亦然,一个 SAPI 节点可能会与多个调用它的 APK 节点存在依赖关系。这些依赖关系提供了丰富的信息,不仅可以衡量特定 APK 对 SAPI 的重要性,还可以描述它们在整个 APK 样本中的全局分布情况。受到通常用于衡量自然语言处理(NLP)中特定文档中某个词重要性的词频 - 逆文档频率(TF-IDF)这一想法的启发,我们提出了一种 APK-SAPI 边缘权重分配方法。假设 APKs = {apk1, apk2, ..., apkN} 和 SAPI = {sapi1, sapi2, ..., sapiK}。对于任何边 <APKj, SAPIi>,其中 1 ≤ j ≤ N,1 ≤ i ≤ K,其边权重根据公式(1-3)进行分配,其中 ni,j 表示 APKj 调用 SAPIi 的次数,I(APKj, SAPIi) 是一个指示函数,当 APKj 调用 SAPIi 时等于 1,否则等于 0。
在此,式(1)通过计算 SAPIi 的调用次数与 APKj 中所有 API 调用次数总和的比值来衡量其重要性。调用某个 API 的次数越多,该 API 的重要性就越高。式(2)通过计算调用该 API 的 APK 数量与所有 APK 数量的反比值来衡量 SAPIi 的偏好程度。调用该 API 的 APK 数量越多,该 API 的重要性就越低。换句话说,如果某个 SAPI 很频繁地被特定的 APK 调用,但很少被其他 APK 调用,这表明该 SAPI 作为分类特征具有良好的区分能力。然而,这种 APK-SAPI 边缘权重分配仅考虑了 SAPI 与调用它的 APK 之间的定量关系,而忽略了 SAPI 在良性与恶意之间分布的差异。为了进一步增强 APK-SAPI 边缘权重的可靠性,我们引入了一个灵敏度系数 δ 来衡量这种分布差异。其计算方法也借鉴了 TF-IDF 机制。对于 SAPIi 而言,其灵敏系数 δi 是通过公式(4)计算得出的,其中 mci 和 bci 分别代表恶意软件和良性软件调用 SAPIi 的数量。
最后,边 <APKj, SAPIi> 的权重由 TF IDFi,j 与 δi 的乘积确定,记为 wji = TF IDFi,j ∗ δi 。
3.3.2. SAPI-SAPI 边缘权重分配
通常情况下,Android 应用程序需要调用一组系统 API 来实现特定的功能,而非仅仅调用一个系统 API。因此,API 调用顺序提供了捕捉 SAPI 之间关系的有用上下文信息,这些关系可以进一步用于为 SAPI-SAPI 边缘分配权重。为了实现这一目标,我们提出了一种 SAPI-SAPI 边缘权重分配方法,包含两个步骤:SAPI 表示学习和 SAPI 相似性度量。首先,我们通过基于 skip-gram(Mikolov 等人,2013 年)模型的无监督学习方法获取 SAPI 的分布式表示,该模型借鉴自 word2vec。选择 skip-gram 模型的原因在于它适用于序列,并且在捕捉上下文窗口内 API 的共现关系方面具有良好的潜力,从而使具有相似上下文的 API 具有相似的语义。为了准备基于 skip-gram 的嵌入模型训练所需的关于 API 使用模式的语料库,我们采用滑动窗口将方法级别的 API 调用序列划分为若干子序列。然而,由于方法级别的 SAPI 调用序列通常不够长,不恰当的滑动窗口设置可能会导致训练语料库不足,进而对最终的嵌入模型产生负面影响。为了解决这个问题,我们设计了两种语料库构建策略。第一种策略考虑的是完整的方法级别 API 调用序列而非方法级别的 SAPI 调用子序列,这不仅解决了滑动窗口设置的问题,而且通过将常见的 API 视为上下文的一部分提供了更多的语义信息。与第一种策略不同的是,第二种策略关注的是类级别 SAPI 调用序列而非方法级别的 API 调用序列,从而创建了足够大的语料库。使用构建好的语料库,基于 skip-gram 模型的无监督学习方法被用于为每个 SAPI 嵌入获取一个向量。skip-gram 算法的本质是根据目标 API 预测上下文 API,而模型训练的目标是根据目标 API 计算其他 API 的出现概率。在完成嵌入模型的训练之后,任何两个语义相似的 API 在嵌入序列中都会相邻排列。给定一条边 <SAPIi, SAPIj>,它们的向量分别表示为 veci 和 vecj。随后,可以使用 veci 和 vecj 的余弦相似度来为 <SAPIi, SAPIj> 这条边分配权重,如公式(5)所示。选择余弦相似度作为权重的动机如下。首先,余弦相似度是一种常规的度量方式,并且已在许多场景中成功应用,尤其是在自然语言处理(NLP)领域。其次,在 API 表示学习过程中,初始向量中的每个维度都代表指定一个 API 时另一个 API 的共现概率,这使得相似度自然地落在 0 到 1 的区间内。将相似度作为边的权重,SAPI 之间的相似度越高,共现关系就越强。
3.4. 温室气体嵌入(GHG 编码)
在构建了一个用于表征整个训练数据集的温室气体(GHG)模型之后,我们学习了用于恶意软件检测的图节点嵌入。尽管图卷积网络(GCN)已在安卓恶意软件检测中得到广泛应用,但在图嵌入过程中,GCN 所使用的目标图通常是具有相同节点和边类型、由固定节点构成的同质图,且是基于单个安卓应用程序构建的。显然,我们在工作中构建的 GHG 与之前使用的图不同,因此 GCN 无法直接应用于 GHG 来学习节点表示,原因如下。对于恶意软件检测,GHG 不是固定的,因为新的恶意软件作为节点可以添加到其中。然而,GCN 基于归纳学习,其学习过程只能在固定的图上进行,在迭代过程中所有节点都用于表示学习。因此,当向图中添加新节点和边时,模型必须重新训练,这极大地限制了 GCN 的实时性能。为了解决这个问题,我们提出了一种基于两级 GCN 的网络,在图中对 GHG 进行图嵌入,如图 4 所示。我们的方法首先针对给定的目标 APK 在图中进行邻域采样,这消除了在图中添加新节点时需要更新整个图中所有节点的需求。我们分别以一阶和二阶方式进行采样,并使用边权重初始化这些节点嵌入。然后,将这些初始化的节点嵌入输入到第一层 GCN 中,在此过程中,目标节点的嵌入通过完全聚合其一阶邻域节点的特征进行更新。目标节点更新后的嵌入以及一阶和二阶节点的嵌入一起被输入到第二层 GCN 中,在此过程中,目标节点的嵌入再次通过完全聚合所有邻域节点的特征进行更新。目标节点及其类别标签的最终嵌入被视为一个训练样本。最后,通过遍历 GHG 中的所有 APK 节点获取所有训练样本,基于监督方法训练一个恶意软件分类器。
3.4.1. 邻域采样
由于恶意软件检测的目标是识别恶意的 APK 文件,因此我们将 APK 类型的节点作为采样目标。给定一个 APK 节点 APKv,我们进行 k 阶邻域采样以捕获目标 APK 的上下文信息,如算法 1 所示。给定一个 APK 节点 APKv,我们使用采样子图 GHG(APKv) 对目标 APK 进行 k 阶邻域采样,如算法 1 所示。假设第 i 阶(1 ≤ i ≤ k)的采样邻域数量用 si 表示。首先,在第 1 行中通过将目标节点 APKv 添加到子图中来初始化子图。其次,在第 3 到第 14 行中迭代进行 k 阶采样。对于每次迭代,第 5 行获取目标节点的所有邻居,并使用函数 getNeighbors() 按照与目标节点的边权重从高到低对其进行排序。需要注意的是,当 k = 1 时,目标节点的邻居类型必须是 SAPI,因为目标节点是一个 APK,而当 k ≥ 2 时,每次迭代中新生成的目标节点的类型可能是 SPAI 或 APK。我们的抽样策略通过目标 APK 与其相邻节点的边权重来控制所抽取节点集的规模。我们在第 6 行至第 10 行实现了这样的抽样策略。具体而言,对于第 i 阶抽样,如果目标节点的相邻节点数量大于 si,那么在第 7 行使用函数 removeLastNodes() 仅保留具有最高边权重的 si 个相邻节点。另一方面,如果目标节点的相邻节点数量小于 si,那么在第 9 行使用函数 addHighestNodes() 以重复抽样的方式将那些具有高边权重的相邻节点添加到目标 APK 的抽样节点集中。在获取抽样相邻节点后,我们在第 12 行使用函数 addNodesToGHG() 将它们添加到子图中,并在第 13 行使用函数 setNewTargetNodes() 将它们设置为下一个阶抽样时的目标节点的新值。一旦完成 k 阶抽样,我们就获得了作为目标节点 APKv 上下文的子图 GHG(APKv)。为了更好地理解抽样过程,我们给出了一个示例,如图 5 所示。在这个示例中,我们设 k = 2,s1 = 3,s2 = 5。对于第一阶抽样,目标 APK 的相邻节点数量为 4,大于 s1。因此,我们从目标 APK 出发,移除边权重最小的邻接节点。对于第二级采样,我们将第一级采样中选取的节点视为新的目标节点。通过依次遍历这些目标节点,并重复第一级采样的过程,我们得到了一个采样子图,HGH(APKv),用红色矩形标记出来。
3.4.2. APK 表示学习
现在我们开发了一种基于多层堆叠 GCN 的表示学习算法来获取 APK 嵌入,如算法 2 所示。假设网络的层数为 k,第 i 层网络的权重矩阵为 Wi,在训练过程中随机初始化并进行调整,Nv 表示 GHG(APKv)的节点集。这里,层数 k 与采样顺序一致,因为目标节点的采样上下文决定了每个节点只能聚合 k 跳范围内的那些节点。第 1 行首先初始化参与采样子图 GHG(APKv)的节点对应的嵌入向量。由于图上有两种类型的节点,我们根据其节点类型进行初始化。对于 APK 类型的节点,其初始嵌入向量使用 APK-SAPI 的边权重初始化,而对于 SAPI 类型的节点,其初始嵌入向量使用 SAPI-SAPI 的边权重初始化。这些向量的维度等于 GHG 中 SAPI 的数量。因此,对于任何节点 u ∈ Nv,我们获得其初始化向量,记为 hu0。然后,以这些初始化向量作为输入,第 2 行至第 5 行通过逐层从子图中获取其相邻节点的信息并进行聚合来学习目标节点 APKv 的最终嵌入。假设当前层位于第 i 层,Niv 表示 APKv 的第 i 个阶邻域,hiv 表示目标 APKv 的表示向量。第 3 行使用平均策略通过 Eq. (6) 获取聚合嵌入 hi,其依据是其一阶邻域的嵌入。在经过第 i 层后,第 4 行根据 Eq. (7) 通过前向传播更新 hiv,其中 hi 1 v 是来自上一层学习到的向量,hi 表示 APKv 直接邻域的聚合嵌入,σ 是一个激活函数。至此,我们得到了最终的嵌入向量。
同样地,为了理解表示学习过程,我们给出一个示例,如图 6 所示。我们旨在使用两层 GCN 学习目标 APK 节点 A 的嵌入 h2A。图 6(a)展示了经过邻居采样后的子图。利用该子图,图 6(b)在第一层仅聚合来自一阶邻居 {B,C,D} 的信息来学习嵌入 h1A。在第一层之后,我们通过第二层网络学习最终嵌入 h2A,该网络由图 6(c)和图 6(d)分别表示的两个步骤组成。在图 6(c)中,目标节点 A 的一阶邻居的嵌入使用其对应的二阶邻居进行更新,然后在图 6(d)中,目标节点 A 的嵌入使用其新更新的一阶邻居进行更新。完成模型训练后,我们得到目标 APK 节点 A 的最终嵌入。
3.5. 模型训练与检测
利用已学习到的 APK 嵌入向量,我们以监督学习的方式构建了一个恶意软件分类器,用于识别应用程序是良性还是恶意。为实现这一目标,我们将 k 层堆叠图卷积网络中最后一层输出的大小设置为要分类的类别数量,从而使模型能够直接用于恶意软件分类。在训练过程中,模型的损失函数采用交叉熵函数,如公式(8)所示,其中 N 表示样本总数,c = 0 表示良性,c = 1 表示恶意。 ̂yi,c 是分类器对样本 i 属于 c 类别的概率预测,而 yi,c 表示真实标签。
损失函数 L(yi,c, ̂yi,c) = ∑i=1N ∑c=0,1 yi,clog ̂yi,c (8)
完成训练过程后,模型被部署到线上,以确定新提交的 APK 是否为恶意软件。由于新提交的 APK 不在训练集中,因此 GHG 中不包含它。因此,基于训练样本构建的 GHG 应该进行更新。首先创建一个对应于新提交 APK 的新节点,记为 v',并将其添加到 GHG 中。然后,对于任何 SAPI 类型的节点 u,如果 v' 调用了 u,则使用 APK-SAPI 边分配算法在 GHG 中添加 v' 和 u 之间的边。最后,获取节点 v' 的一组邻接节点 N(v') 的初始嵌入以及节点 v' 的初始嵌入,并将其输入模型以输出检测结果。
4.实验
在本节中,我们在来自多个真实世界安卓应用市场的大型数据集上对 GHGDroid 进行评估。首先,我们将描述数据集、评估指标以及相关的实验细节。然后,我们将从性能和效率方面报告实验结果。
4.1. 实验设置
我们实验中所使用的数据集包含从多个市场(包括官方的谷歌应用商店、安智市场以及其他研究人员公开发布的数据集)收集的 20734 个良性应用和 23163 个恶意应用。所用数据集的详细信息见表 1。我们检查了数据集中每个应用的签名和包信息以避免重复。在实验中,前三个数据集按照 8:2 的比例划分为训练集和测试集。在测试集上表现最佳的模型被保留下来,并在剩余的第 4 和第 5 个数据集上进一步进行性能和效率评估。我们在实验中使用经典的指标来评估检测模型的分类性能,如表 2 所示。准确率表示数据集中正确分类的安卓应用所占的百分比。精确率是预测为正样本中真正为正样本的比例。召回率是所有预测为正样本中良性安卓应用所占的比例。F1 分数是准确率和召回率的调和平均值,用于评估检测恶意安卓应用程序的能力。我们在 Python 中实现了我们的方法,并将其发布在 Github 上(https://github.com/njustbdag/GHGDroid)。所有实验均在配备 240GB 内存、8TB 存储空间以及英特尔至强 E5-2678v3 @ 2.50GHz CPU 的服务器上进行。
4.2. 整体性能
为了展示 GHGDroid 的有效性,我们从准确率、召回率、准确度和 F1 值等方面报告其结果,并将其与五种具有代表性的方法进行比较,即 MaMaDroid(Onwuzurike 等人,2019 年)、DAPASA(Fan 等人,2017 年)、DroidSim(Sun 等人,2014 年)、S3Feature(Ou 和 Xu,2022 年)以及 HinDroid(Hou 等人,2017 年)。选择这些检测方法的原因在于它们都与 GHGDroid 有着相似的理念,即基于 API 调用捕获 APK 的行为特征。在这些被比较的方法中,MaMaDroid 是唯一一种基于序列的方法,它本质上利用 API 调用的序列性,基于马尔可夫模型挖掘和生成特征。其余的方法都是基于图的方法。DAPASA 和 S3Feature 侧重于敏感子图挖掘。DroidSim 基于同质函数调用图,而 HinDroid 基于异质函数调用图。HinDroid 与我们的工作最为接近,因为它也构建了一个异质图。然而,它主要关注图中的路径相似性,并未充分利用图中的信息。此外,上述方法的开源代码可供复制。表 3 展示了实验结果。首先,与基于序列的方法 MaMaDroid 相比,所有基于图的方法表现更优。F1 分数的最小和最大提升分别达到了 5.4% 和 11.25%,这表明基于图的解决方案在提升恶意软件检测方法的检测性能方面具有良好的潜力。其次,我们可以看到 GHGDroid 在所有指标上都优于其他所有对比方法,这表明通过 GHG 捕获的 APK 行为特征能够有效区分良性 APK 和恶意 APK。主要原因在于 GHGDroid 不仅利用了 API 调用的序列性,通过邻域采样技术从局部视角捕获 API 的语义信息,还从全局视角将 APK 与 SAPI 之间的丰富关系信息整合到 GHG 中。实际上,GHGDroid 结合了基于序列的解决方案和基于图的解决方案,从而取得了卓越的性能。
第三,我们还观察到 S3Feature 相较于其他代表性方法更为突出。DAPASA 是与 S3Feature 最相似的工作,因为两者都是通过从给定 APK 构建的图中提取的子图来识别恶意软件。然而,S3Feature 在子图挖掘方面与 DAPASA 有显著不同。具体而言,DAPASA 仅使用得分最高的子图进行恶意软件检测,而 S3Feature 则充分利用一组邻接子图。此外,在为检测模型训练准备特征向量时,DAPASA 仅从选定的子图中提取五种类型的特征,而 S3Feature 则通过图哈希技术对所有子图进行编码。显然,S3Feature 表现优于 DAPASA 是得益于利用了更丰富的信息。尽管 DroidSim 和 HinDroid 也属于基于图的方法,但它们在图的类型、图的使用等方面与 S3Feature 有明显不同,这导致了检测性能上的差异。从表 3 可以看出,S3Feature 略优于 DroidSim 和 HinDroid。最后,与表现最佳的方法 S3Feature 相比,GHGDroid 在 F1 分数上略有提高,提高了 0.89%,达到 99.17%。GHGDroid 检测性能高的原因如下。GHGDroid 采用更复杂的基于神经网络的模型,从构建的图中自动学习特征,并基于所学特征训练分类模型。显然,特征学习和模型训练密切相关,整个过程是连贯的。另一方面,S3Feature 通过哈希算法从构建的图中提取的子图获取特征,然后应用传统的机器学习算法训练模型。相反,S3Feature 中涉及的特征学习和模型训练是分开的。因此,更复杂的模型和训练过程可能是 GHGDroid 和 S3Feature 性能差异的原因。4.3. 消融实验
为了更好地理解为何所提出的 GHG 能够从全局和局部视角捕捉 APK 的行为特征,我们开展了一组实验,通过改变边权重分配策略和 API 调用序列采样策略来构建 GHG 的不同变体,从而评估 GHG 中每个组件对整体性能的贡献。我们在保持其余检测方法不变的情况下,使用这些变体进行实验,如表 4 所示。Base 表示没有边权重的基本 GHG。TI 在基本 GHG 的基础上构建了考虑 APK-SAPI 边权重的图。TI*δ
在 TI 类型的 GHG 中引入了 API 敏感度系数 δ。SG 是一种在基本 GHG 中添加 SAPI-SAPI 边权重的 GHG,有三种类型,分别对应不同的 API 调用序列构建策略。SG1 对应方法级敏感 API 序列,SG2 对应方法级的所有 API 序列,SG3 对应类级敏感 API 序列。
4.4. 效率分析
在本节中,我们对模型的效率进行分析,仅关注检测过程所花费的时间,而非训练过程所花费的时间。排除数据预处理过程中解压 APK 所需的时间,每个 APK 的检测时间主要由以下三部分组成:识别 APK 中涉及的敏感 API 调用所花费的时间、更新当前 GHG(通用危害等级)所花费的时间以及使用检测模型进行分类所花费的时间。我们从这些方面报告了时间消耗情况,如图 7 至图 9 所示。从图 7 可以看出,识别敏感 API 调用所花费的时间取决于 APK 的大小。APK 的代码大小越大,所包含的文件就越少,遍历这些 smali 文件以提取 API 所花费的时间就越少。通过对数据集中所有样本的调用识别时间进行分析,我们得出该步骤平均每 APK 所花费的时间为 1.63 秒。从图 8 可以观察到,当检测 APK 对应的新节点添加时,更新 GHG 所花费的时间几乎与训练样本的大小呈线性增长关系。我们考虑了从 5000 到 25000 个样本的五个案例,样本大小每次增加 5000。具体而言,当训练样本的规模为 5000 时,更新 GHG 的平均耗时为 0.43 秒;而当训练样本的规模增加五倍时,更新 GHG 的平均耗时则为 2.39 秒,这表明 GHG 越复杂,更新它所需的时间就越长。
最后,我们给出了模型所花费的检测时间,如图 9 所示。我们的检测模型将更新后的 GHG(温室气体)和目标节点作为输入,并输出分类结果,即良性或恶意。分类所需的时间包含邻接节点采样、APK 表示学习以及模型分类的时间。从图 9 中我们可以发现,与识别敏感 API 所需的时间以及更新 GHG 所需的时间相比,检测所需的时间更短,并且随着训练集规模的增大呈现出大致线性增长的趋势。具体而言,当训练样本的大小为 5000 时,平均检测时间约为 1.99 毫秒(ms),而当训练样本的大小增加五倍时,检测时间则为 9.86 ms。从上述观察中,我们可以得出结论,检测时间主要取决于 APK 的大小和训练样本的数量。在我们实验中所考虑的最坏情况下,检测时间少于 8 秒,其中约 5.5 秒用于识别敏感的应用程序接口(API),2.39 秒用于更新温室气体(GHG),这在效率方面能够满足实际应用的要求。为了进一步展示效率方面的优势,我们将 GHGDriod 与五种具有代表性的基于图的恶意软件检测方法进行了比较,其中排除了 MaMaDroid,因为它基于序列特征而非图。对于一个 APK 文件,使用这些基于图的恶意软件检测方法的检测过程可以分为四个步骤,包括 APK 解析、图重建、表示学习和模型推理。由于在 APK 解析阶段所有方法共享几乎相似的静态分析以获取构建图所需的信息,我们不再讨论其时间成本。APK 解析的平均时间是 4.42 秒。此外,所有方法的模型推理都可以在毫秒内完成。因此,我们关注图构建和表示学习的时间。表 5 展示了每个步骤所花费的平均时间。从表 5 中我们可以看出,GHGDroid 在检测时间方面表现最佳。具体而言,在图构建方面,DroidSim 所花费的时间最长,因为 DroidSim 构建的 CFG(控制流图)与其他方法中使用的 FCG(功能控制流图)相比是一种更精细粒度的图。在使用 FCG 的方法中,GHGDroid 所花费的时间最长,而 S3Feature 所花费的时间最短。主要原因在于 GHGDroid、DAPASA 和 Hin Droid 的图重建的时间复杂度为 O(N2),而 S3Feature 为 O(N + M),其中 N 是节点数量,M 是边的数量。在表示学习方面,GHGDroid 所花费的时间极短,因为 GHGDroid 中更新的图直接被输入到训练有少量参数的两层基于 GCN(图卷积网络)的模型中以获得其分布式表示,而其他方法在学习其表示之前必须执行一些额外的操作。例如,DAPASA 和 S3Feature 花费额外的时间从构建的图中提取子图,然后为每个子图获取表示,这导致了更多的时间开销。总体而言,GHGDroid 在恶意软件检测方面表现出很高的效率。
4.5. 敏感性分析
由于 GHGDriod 包含两个关键参数,即训练集的大小和层数,我们进行了另一组实验来探究它们对检测模型性能和效率的影响。首先,我们评估了训练集大小对检测性能的影响。GHG 包含两种类型的节点:APK 和 SAPI。APK 节点的数量等于训练集的大小,而 SAPI 节点的数量取决于训练集中 APK 调用的 SAPI 数量。表 6 给出了通过改变训练集大小在精度、召回率、准确率和 F1 分数方面的实验结果。从表 6 中可以看出,随着训练集大小的增加,模型的性能也随之提高,这表明更大的训练集有助于实现更好的性能。同时,我们还发现当训练集大小超过 15,000 时,检测性能的提升非常微小。其原因在于随着训练集大小的增加,新发现的 SAPI 的数量逐渐减少。在性能提升与新发现的 SAPI 数量之间的趋势是相同的,这表明 SAPI 在提升检测模型的性能方面发挥着重要作用。接下来,我们评估参数 k 对检测模型性能的影响。参数 k 决定了采样策略中邻域节点的大小以及节点聚合更新中的堆叠网络层的数量。我们将 k 变化范围设定为 1 到 5,并在表 7 中报告结果。当 k = 1 时,模型表现不佳。原因是第一阶邻域采样只能聚合其直接邻域节点的信息,这无法有效地利用全局结构特性。当 k = 2 时,我们实现了最佳的 F1 分数 99.17%,与单层网络结构相比提高了 9.9%。当 k > 2 时,随着层数的增加,四个性能指标呈现出下降的趋势,分别下降了 1.03%、2.6%和 3.73%。网络中的层数越多,F1 分数下降得越快,这表明更丰富的采样和更复杂的网络结构并不总是有助于提高性能。增加网络的深度可能会导致邻居采样和聚合传播到更远的节点,包括过多且不相关的信息,稀释重要的特征信息,并导致检测性能的下降。因此,一个两层的网络结构足以聚合 APK-SAPI、APKSAPI-APK 和 APK-SAPI-SAPI 路径信息,使 APK 节点能够获取恶意应用程序分类所需的相关特征信息。此外,网络层数的增加会导致模型更加复杂,并且检测时间成本更高,如图 10 所示。我们可以发现,随着网络层数的增加,分类所需的时间急剧上升,这是因为模型参数的数量呈指数级增长。